{The unit Titrate controls the form SweepForm, and allows the user to }
{set the parameters for sweeping a single constraint value, calculating }
{equilibrium at each point, displaying the results and saving the results }

unit Titrate;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, TitrDefs, Solver, StdCtrls, ExtCtrls, Editor, Grids, Buttons,
  Menus, TeeProcs, TeEngine, Chart, Series, Math;

type
  TSweepForm = class(TForm)
    Label1: TLabel;
    TitleEdit: TEdit;
    CompList: TComboBox;
    Label3: TLabel;
    Label4: TLabel;
    Label5: TLabel;
    Label6: TLabel;
    Initial: TEdit;
    IncrEdit: TEdit;
    PointsEdit: TEdit;
    Final: TEdit;
    Label7: TLabel;
    TitrTypeDescrip: TEdit;
    SweepBtn: TButton;
    TiDataGrid: TStringGrid;
    DefLabel: TStaticText;
    MainMenu1: TMainMenu;
    File1: TMenuItem;
    Exit1: TMenuItem;
    Save1: TMenuItem;
    New1: TMenuItem;
    Editing: TMenuItem;
    EditSystem: TMenuItem;
    EditParams: TMenuItem;
    SweepSaveDialog: TSaveDialog;
    TitrGraph: TChart;
    YSelect: TComboBox;
    Label8: TLabel;
    Series1: TLineSeries;
    Y2Select: TComboBox;
    Y3Select: TComboBox;
    Y4Select: TComboBox;
    Y5Select: TComboBox;
    Label9: TLabel;
    Label10: TLabel;
    Label11: TLabel;
    Label12: TLabel;
    Series2: TLineSeries;
    Series3: TLineSeries;
    Series4: TLineSeries;
    Series5: TLineSeries;
    Sweep: TMenuItem;
    MenuHelp: TMenuItem;
    MenuExit: TMenuItem;
    About1: TMenuItem;
    Topics: TMenuItem;
    Bevel1: TBevel;
    Bevel2: TBevel;
    Label13: TLabel;
    Label14: TLabel;
    Label15: TLabel;
    LogMol: TRadioGroup;

    Procedure DefaultTitr;
    Procedure WriteScreen;
    procedure FormActivate(Sender: TObject);
    procedure TitleEditExit(Sender: TObject);
    procedure CompListExit(Sender: TObject);
    procedure PointsEditExit(Sender: TObject);
    procedure IncrEditExit(Sender: TObject);
    Procedure WriteTiResults;
    Procedure ClearResults;
    procedure SweepBtnClick(Sender: TObject);
    procedure ExitBtnClick(Sender: TObject);
    Procedure SaveResults;
    procedure Save1Click(Sender: TObject);
    procedure Exit1Click(Sender: TObject);
    procedure ExportBtnClick(Sender: TObject);
    procedure EditSystemClick(Sender: TObject);
    procedure EditParamsClick(Sender: TObject);

    procedure PlotY1(Conc : integer);
    procedure PlotY2(Conc : integer);
    procedure PlotY3(Conc : integer);
    procedure PlotY4(Conc : integer);
    procedure PlotY5(Conc : integer);
    Procedure PlotAll;
    procedure YSelectChange(Sender: TObject);
    procedure Y2SelectChange(Sender: TObject);
    procedure Y3SelectChange(Sender: TObject);
    procedure Y4SelectChange(Sender: TObject);
    procedure Y5SelectChange(Sender: TObject);
    procedure New1Click(Sender: TObject);
    procedure MenuExitClick(Sender: TObject);
    procedure About1Click(Sender: TObject);
    procedure TopicsClick(Sender: TObject);
    Procedure LinearPlot;
    procedure LogMolClick(Sender: TObject);

  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  SweepForm: TSweepForm;

{****************************************************************************}
{****************************************************************************}

implementation

uses ParamEdit, TitrHelp;

{$R *.dfm}

{DefaultTitr sets the Sweep control parameters to the default values}

Procedure TSweepForm.DefaultTitr;

Var  i, com, spe : integer;     {counters}

begin
  TitrPts := 0;                 { initialize Sweep conditions }
  TiType := TiNone;
  Delta  := 0;                  { increment set to 0}
  TitrX := 0;                   { No component to selected titrate }
  XData[1] := 0;                { for display only}
  InitialPt := 0;               { initial and final points of Sweep}
  FinalPt := 0;                 { are set to zero }
  SweepDone := False;       { titration not calculated}
  fillchar(TitrHead,sizeof(TitrHead),0);   {no title }

   LogMolar := 1;                 { Log scale on graph }

  {Place options in to the series selection combo boxes, 0 = no selection}

    YSelect.Items.Clear;
    YSelect.Items.Add('None selected');
    For com := 1 to S.NComp do
       i := Yselect.Items.add(S.Comps[com].Name);
    For spe := 1 to S.NSpec do
       i := YSelect.Items.add(S.Specs[spe].Name);

    YSelect.ItemIndex := 0;
    Y2Select.Items := YSelect.Items;   Y2Select.ItemIndex := 0;
    Y3Select.Items := YSelect.Items;   Y3Select.ItemIndex := 0;
    Y4Select.Items := YSelect.Items;   Y4Select.ItemIndex := 0;
    Y5Select.Items := YSelect.Items;   Y5Select.ItemIndex := 0;
 end;



{WriteScreen writes in values for the various editing controls on the Sweep}
{screen (SweepForm)}

Procedure TSweepForm.WriteScreen;
Var com, i : integer;

begin

   {Write in the title of the Sweep data, if any}
   TitleEdit.Text := TitrHead.Title;
   DefLabel.Caption := 'Definition: ' + S.Head.Title;

   {Write the various component names into the dropdown list CompList}
   CompList.Items.Clear;
   CompList.Items.Add('None Selected');
   For com := 1 to S.NComp do
       i := CompList.Items.add(S.Comps[com].Name);

   {Write in the text for the editing controls}
   Initial.Text := FloatToStrF(InitialPt, ffExponent, 3, 8);
   IncrEdit.Text := FloatToStrF(Delta, ffExponent, 3, 8);
   PointsEdit.Text := IntToStr(TitrPts);
   Final.Text := FloatToStrF(FinalPt, ffExponent, 3, 8);
   CompList.ItemIndex := TitrX;

   {If a component has been selected to titrate, then write in that information}
   If (TitrX > 0) then begin
       If (S.comps[TitrX].CType = CtotDiss) then         {Sweep type}
          TitrTypeDescrip.Text := 'Titrate Total Known'
           else TitrTypeDescrip.Text := 'Speciation Diagram';
     end
    else
      TitrTypeDescrip.Text := 'None selected';

    LogMol.ItemIndex := LogMolar;


end;

{Whenever the form is activated, clear the settings and results and}
{display a blank form}

procedure TSweepForm.FormActivate(Sender: TObject);
begin
   DefaultTitr;
   WriteScreen;
   ClearResults;
end;

{Allows user to change title of Sweep data}

procedure TSweepForm.TitleEditExit(Sender: TObject);
begin
  TitrHead.Title := TitleEdit.Text;
end;

{CompListExit is invoked whenever the drop-down list of components has been }
{exited- presumably after the user has changed the component to titrate}
{The new component choice is recorded in TitrX, the initial and final }
{points of the Sweep are determined, the new information is displayed}

procedure TSweepForm.CompListExit(Sender: TObject);
begin
   TitrX := CompList.ItemIndex;                  {Record new titrated component}
   If (S.Comps[TitrX].CType = CTotDiss) then     {Determine new InitialPt value}
        InitialPt := S.Comps[TitrX].TotalX       {Depending on type}
        else InitialPt := S.Comps[TitrX].GuessX;

   FinalPt := InitialPt + Delta * (TitrPts-1);     {Determine new finalPt}

   Initial.Text := FloatToStrF(InitialPt, ffExponent, 3, 8);  {Display values}
   Final.Text :=  FloatToStrF(FinalPt, ffExponent, 3, 8);

   If (S.comps[TitrX].CType = CtotDiss) then begin     {Display Sweep type}
       TitrTypeDescrip.Text := 'Sweep Total Known';
       TitrGraph.Title.Text.Text := 'Sweep Results';
       TiType := TiTotal;
      end
       else begin
         TitrTypeDescrip.Text := 'Speciation Diagram';
         TitrGraph.Title.Text.Text := 'Speciation Diagram';
         TiType := TiFree;
        end;

   SweepDone := False;                       {Clear any preceding results}
   ClearResults;
end;

{PointsEditExit gets the number of Sweep data points, checks for valid}
{values (at least 3), then calculates the new FinalPt and displays the text}

procedure TSweepForm.PointsEditExit(Sender: TObject);
begin
    PointsEdit.Text := WriteIntEdit(PointsEdit.Text, TitrPts, 3, NDataPts);
    FinalPt := InitialPt + Delta * (TitrPts-1);
    Final.Text :=  FloatToStrF(FinalPt, ffExponent, 3, 8);
    SweepDone := False;
    ClearResults;
end;

{IncrEditExit gets the new Sweep increment, checks for valid}
{values, then calculates the new FinalPt and displays the text}

procedure TSweepForm.IncrEditExit(Sender: TObject);
begin
   IncrEdit.Text := WriteRealEdit(IncrEdit.Text, Delta, -1, 1);
   FinalPt := InitialPt + Delta * (TitrPts-1);
   Final.Text :=  FloatToStrF(FinalPt, ffExponent, 3, 8);
   SweepDone := False;
   ClearResults;
end;

{The procedure WriteTiResults writes the current Sweep results from }
{arrays XData and YData into the string grid TiDataGrid for user inspection}

Procedure TSweepForm.WriteTiResults;

Var x, com, spe : integer;                     {counts columns and rows}
    XTitle : string;
    i     : integer;

begin
   {First resize the results grid}
   TiDataGrid.RowCount := TitrPts + 1;
   TiDataGrid.ColCount := S.NSpec + S.Ncomp + 1;
   TiDataGrid.FixedCols := 1;
   TiDatagrid.FixedRows := 1;

   {Next write the header information in the top row}
   If (TiType = TiTotal) then
        Xtitle := 'Total ' + S.Comps[Titrx].name + ' ' + XUnit[MaxOrd]

      else  Xtitle := 'Free ' + S.Comps[Titrx].name;

   SweepForm.TiDataGrid.Cells[0, 0] := Xtitle;

   For com := 1 to S.NComp do
       SweepForm.TiDataGrid.Cells[com, 0] := S.Comps[com].Name;

   For spe := 1 to S.NSpec do
       SweepForm.TiDataGrid.Cells[spe + S.NComp, 0] := S.Specs[spe].Name;

   {Now write the contents of Xdata and YData to the grid}
   For x:= 1 to TitrPts do begin
     SweepForm.TiDataGrid.Cells[0, x] := FloatToStrF(Xdata[x], ffExponent, 4,3);
     For com := 1 to (S.NComp + S.NSpec) do
        SweepForm.TiDataGrid.Cells[com, x] :=
           FloatToStrF(Ydata[com, x], ffExponent, 4,3);

    end;

    {Now clear the results graph}
    TitrGraph.LeftAxis.Automatic := True;
    TitrGraph.BottomAxis.Title.Caption := XTitle;

    {And by default graph the first component concentration }

    Series1.Title := YSelect.Items[1];
    YSelect.ItemIndex := 1;
    LogMolar := 1;
    LogMol.ItemIndex := 1;
    PlotY1(1);
    Series2.Clear;  Series3.Clear; Series4.Clear;  Series5.Clear;

end;

Procedure TSweepForm.ClearResults;

begin
  SweepDone := False;
  {Size the data grid to a single cell and empty it}
  SweepForm.TiDataGrid.RowCount := 1;
  SweepForm.TiDataGrid.ColCount := 1;
  SweepForm.TiDataGrid.Cells[0, 0] := '';
  SweepForm.TitrGraph.BottomAxis.Title.Caption := '';

  {Clear out the data series for plotting and their titles}
  Series1.Clear; Series1.Title := ''; YSelect.ItemIndex := 0;
  Series2.Clear; Series2.Title := ''; Y2Select.ItemIndex := 0;
  Series3.Clear; Series3.Title := ''; Y3Select.ItemIndex := 0;
  Series4.Clear; Series4.Title := ''; Y4Select.ItemIndex := 0;
  Series5.Clear; Series5.Title := ''; Y5Select.ItemIndex := 0;

end;                               {End of ClearResults}

procedure RestoreInitial;
begin
   If (TiType = TiTotal) then
      S.Comps[TitrX].TotalX := InitialPt;
   If (TiType = TiFree) then
      S.comps[TitrX].GuessX := InitialPt;

end;

{GetAbMax return the largest absolute value in the first N elements of vector X}

Function GetAbMax(Var X : DataArray; N : integer) : double;
Var TempMax : double;
    i : integer;

begin
   TempMax := 0;
   For i := 0 to N do
      if (abs(X[i]) > TempMax) then
          TempMax := abs(X[i]);
   GetAbMax := TempMax;
end;

{GetYMax returns the largest values in the first N elements of all the }
{Currently plotted Y variables}

Function GetYMax(N : integer) : double;

begin
end;


{SweepBtnClick allows the user to perform a Sweep using previously }
{selected conditions.  First the conditions are checked to be sure that a }
{Sweep can be run,
                 }
procedure TSweepForm.SweepBtnClick(Sender: TObject);

Var i : integer;
    MaxX : double;
begin

    {First check to see if sweep conditions are set}
    If ((TitrPts < 3) or (TiType = TiNone) or (TitrX <1)) then begin
        ShowMessage('You must define sweep conditions before calculating.');
        Exit;
      end;

    ClearResults;
    {Now fill the array XData with values for the swept component}
    SweepDone := False;
    For i := 1 to TitrPts do
        XData[i] := InitialPt + (i-1) * Delta;

    {For sweeps using a 'total known' component, set the X axis to use units}
    { of M, mM, uM, nM, etc.}

    If (TiType = TiTotal) then begin
         MaxX := GetAbMax(XData, TitrPts);
         MaxOrd := -floor(ln(MaxX)/(LogConvr*3));
         If (MaxOrd > 6) then MaxOrd := 6;
         If (MaxOrd < 0) then MaxOrd := 0;
         For i := 1 to TitrPts do
            XPlot[i] := XData[i] * Power(10, 3 * MaxOrd);
       end;

       {For sweeps of a 'log free known' component, just use the linear scale}

    If (TiType = TiFree) then
          For i := 1 to TitrPts do
            XPlot[i] := XData[i];

    {and finally solve using the SweepSolve routine}
    if (Not SweepSolve) then begin
       If (PhaseViol) then
         Showmessage('Phase rule violation- results invalid.');
       If (TooMany) then
         Showmessage('Iteration did not converge- results may be incorrect.');
       RestoreInitial;
       Exit;
     end;

    WriteTiResults;

    SweepDone := True;
    RestoreInitial;
end;

{ExitBtnClick simply closes this form and returns the user to the }
{system definition screen}

procedure TSweepForm.ExitBtnClick(Sender: TObject);
begin
    SweepForm.Close;
end;

{Procedure SaveResults writes the Sweep results in XData and YData to }
{an ASCII file suitable for reading by a spreadsheet }

Procedure TSweepForm.SaveResults;

 Var
    F : TextFile;                     {ASCII text file}
    FileName : String;                {File name to save}
    SaveData : Boolean;               {Was a filename given by user?}
    Ypts     : integer;
    x, y     : integer;               {text line counter}
    com, spe : integer;               {component and species counters}
    dummy    : string;

begin
  If (not SweepDone) then begin
   ShowMessage('You must have performed a sweep with current parameters to save a file.');
   Exit;
  end;

  SaveData := SweepSaveDialog.Execute;      {get name of file to be saved}

  If SaveData then begin                   {if a name is chosen then...}

    If (ofExtensionDifferent in SweepSaveDialog.Options) then begin
        ShowMessage('Please save as a txt file.');
        Exit;
       end;

    FileName := SweepSaveDialog.Filename;
    AssignFile(F, FileName);          { Open file for writing}
         {$I-}

    ReWrite(F);                       { start at the beginning of the file}

  {Give the names of both the system definition used to generate the Sweep}
  {and the results data set, if any}

    Writeln(F, '"System Definition: ' + S.head.title);
    Writeln(F, '"Sweep: ' + Titrhead.title);

  {Next write the names of the variables calculated }

    If (TiType = TiTotal) then dummy := 'Total_' + S.Comps[Titrx].name
      else  dummy := 'Free_' + S.Comps[Titrx].name;

    Write(F, dummy);
    For com := 1 to S.NComp do
        Write(F, S.Comps[com].Name,' ');
    For spe := 1 to S.NSpec do
        Write(F, S.Specs[spe].name, ' ');
    Writeln(F);

    {Finally write the actual data, one line for each x value}

    YPts := S.NComp + S.NSpec;

    For x := 1 to TitrPts do begin
       str(Xdata[x]:14, dummy);
       dummy := trimleft(dummy);
       Write(F, dummy, ' ');
       For y := 1 to YPts do
         Write(F, YData[y, x]:12, ' ');
       WriteLn(F);
      end;

     CloseFile(F);
   end;                           {end if SaveData}

end;                              {end of procedure SaveResults}

{Menu item File/Save should write the current Sweep data to a text }
{file with extension .txt, readable by Excel or similar program}

procedure TSweepForm.Save1Click(Sender: TObject);
begin
  SaveResults;
end;

{Menu item Exit returns user to the system definition screen}

procedure TSweepForm.Exit1Click(Sender: TObject);
begin
    SweepForm.Close;
end;

{Button labeled Export should write the current Sweep data to a text }
{file with extension .ttf, readable by Excel or similar program}

procedure TSweepForm.ExportBtnClick(Sender: TObject);
begin
   SaveResults;
end;
                                        {End of file and unit titrate}
procedure TSweepForm.EditSystemClick(Sender: TObject);
begin
   SweepForm.Close;
end;

procedure TSweepForm.EditParamsClick(Sender: TObject);
begin
   Paramform.Showmodal;
end;




{ The following set of routines (YselectChange, Y2SelectChange, etc.) }
{ is highly repetitive and should be condensed.  These routines permit the user
{ to select dependent variables (concentrations) to be plotted}

procedure TSweepForm.PlotY1(Conc : integer);

Var  x : integer;                   {counter}

begin
 Series1.Clear;                     {clear the plot}
 If (LogMolar = 1) then begin
   for X := 1 to TitrPts do
       If (YData[Conc, X] > 0) then
         Series1.AddXY(XPlot[X], ln(YData[Conc, X])/LogConvr);
       end;                           {end If LogMolar...}
 If (LogMolar = 0) then begin
      for X := 1 to TitrPts do
          Series1.AddXY(XPlot[X], YData[Conc, X]*Power(10, 3 * YOrd));
     end;

end;

procedure TSweepForm.PlotY2(Conc : integer);

Var  x : integer;                   {counter}

begin
 Series2.Clear;                     {clear the plot}
 If (LogMolar = 1) then begin
   for X := 1 to TitrPts do
       If (YData[Conc, X] > 0) then
         Series2.AddXY(XPlot[X], ln(YData[Conc, X])/LogConvr);
       end;                           {end If LogMolar...}
 If (LogMolar = 0) then
      for X := 1 to TitrPts do
           Series2.AddXY(XPlot[X], YData[Conc, X]*Power(10, 3 * YOrd));
end;

 procedure TSweepForm.PlotY3(Conc : integer);

Var  x : integer;                   {counter}

begin
 Series3.Clear;                     {clear the plot}
 If (LogMolar = 1) then begin
   for X := 1 to TitrPts do
       If (YData[Conc, X] > 0) then
         Series3.AddXY(XPlot[X], ln(YData[Conc, X])/LogConvr);
       end;                           {end If LogMolar...}
 If (LogMolar = 0) then
      for X := 1 to TitrPts do
           Series3.AddXY(XPlot[X], YData[Conc, X]*Power(10, 3 * YOrd));
end;

procedure TSweepForm.PlotY4(Conc : integer);

Var  x : integer;                   {counter}

begin
 Series4.Clear;                     {clear the plot}
 If (LogMolar = 1) then begin
   for X := 1 to TitrPts do
       If (YData[Conc, X] > 0) then
         Series4.AddXY(XPlot[X], ln(YData[Conc, X])/LogConvr);
       end;                           {end If LogMolar...}
 If (LogMolar = 0) then
      for X := 1 to TitrPts do
           Series4.AddXY(XPlot[X], YData[Conc, X]*Power(10, 3 * YOrd));
end;

procedure TSweepForm.PlotY5(Conc : integer);

Var  x : integer;                   {counter}

begin
 Series5.Clear;                     {clear the plot}
 If (LogMolar = 1) then begin
   for X := 1 to TitrPts do
       If (YData[Conc, X] > 0) then
         Series5.AddXY(XPlot[X], ln(YData[Conc, X])/LogConvr);
       end;                           {end If LogMolar...}
 If (LogMolar = 0) then
      for X := 1 to TitrPts do
           Series5.AddXY(XPlot[X], YData[Conc, X]*Power(10, 3 * YOrd));
end;

Procedure TSweepForm.PlotAll;

begin
     If (YSelect.ItemIndex > 0) then
        PlotY1(YSelect.ItemIndex);
   If (Y2Select.ItemIndex > 0) then
        PlotY2(Y2Select.ItemIndex);
   If (Y3Select.ItemIndex > 0) then
        PlotY3(Y3Select.ItemIndex);
   If (Y4Select.ItemIndex > 0) then
        PlotY4(Y4Select.ItemIndex);
   If (Y5Select.ItemIndex > 0) then
        PlotY5(Y5Select.ItemIndex);
end;


procedure TSweepForm.YSelectChange(Sender: TObject);
Var
   YVar : integer;
   X    : integer;            {titration point counter}

begin
   If (Not SweepDone) then begin
       ShowMessage('You have no data to plot.');
       YSelect.Itemindex := 0;
      end;

   YVar := YSelect.ItemIndex;     {get the property from the combobox}

   If (YVar > 0) then begin      {it will be 0 if no property is selected}
     Series1.Title := YSelect.Items[YVar];
     If (LogMolar = 0) then begin
         LinearPlot;
         PlotAll;
       end                           {End If Logmolar = 0}
     Else PlotY1(YVar);

    end; {End if YVar > 0}

end;     {End YSelectChange}


procedure TSweepForm.Y2SelectChange(Sender: TObject);
Var
   YVar : integer;
   X    : integer;            {titration point counter}

begin
   If (Not SweepDone) then begin
       ShowMessage('You have no data to plot.');
       Y2Select.Itemindex := 0;
      end;

   YVar := Y2Select.ItemIndex;     {get the property from the combobox}

   If (YVar > 0) then begin      {it will be 0 if no property is selected}
     Series2.Title := Y2Select.Items[YVar];
     If (LogMolar = 0) then begin
         LinearPlot;
         PlotAll;
       end                           {End If Logmolar = 0}
     Else PlotY2(YVar);
     end;

end;     {End Y2SelectChange}

procedure TSweepForm.Y3SelectChange(Sender: TObject);
Var
   YVar : integer;
   X    : integer;            {titration point counter}

begin
   If (Not SweepDone) then begin
       ShowMessage('You have no data to plot.');
       Y3Select.Itemindex := 0;
      end;

   YVar := Y3Select.ItemIndex;     {get the property from the combobox}

   If (YVar > 0) then begin      {it will be 0 if no property is selected}
     Series3.Title := Y3Select.Items[YVar];
     If (LogMolar = 0) then begin
         LinearPlot;
         PlotAll;
       end                           {End If Logmolar = 0}
     Else PlotY3(YVar);
     end;
end;     {End Y3SelectChange}


procedure TSweepForm.Y4SelectChange(Sender: TObject);
Var
   YVar : integer;
   X    : integer;            {titration point counter}

begin
    If (Not SweepDone) then begin
       ShowMessage('You have no data to plot.');
       Y4Select.Itemindex := 0;
      end;

   YVar := Y4Select.ItemIndex;     {get the property from the combobox}

   If (YVar > 0) then begin      {it will be 0 if no property is selected}
     Series4.Title := Y4Select.Items[YVar];
     If (LogMolar = 0) then begin
         LinearPlot;
         PlotAll;
       end                           {End If Logmolar = 0}
     Else PlotY4(YVar);
     end;

end;     {End Y4SelectChange}

procedure TSweepForm.Y5SelectChange(Sender: TObject);
Var
   YVar : integer;
   X    : integer;            {titration point counter}

begin
     If (Not SweepDone) then begin
       ShowMessage('You have no data to plot.');
       Y5Select.Itemindex := 0;
      end;

   YVar := Y5Select.ItemIndex;     {get the property from the combobox}

   If (YVar > 0) then begin      {it will be 0 if no property is selected}
     Series5.Title := Y5Select.Items[YVar];
     If (LogMolar = 0) then begin
         LinearPlot;
         PlotAll;
       end                           {End If Logmolar = 0}
     Else PlotY5(YVar);
     end;

end;     {End Y5SelectChange}

procedure TSweepForm.New1Click(Sender: TObject);
begin
   DefaultTitr;
   ClearResults;
   WriteScreen;
end;

procedure TSweepForm.MenuExitClick(Sender: TObject);
begin
   SweepForm.Close;
end;

procedure TSweepForm.About1Click(Sender: TObject);
begin
   ShowMessage('Titrator Chemical Equilibrium Calculator  v. 3.01 October 2008  SE Cabaniss');
end;

procedure TSweepForm.TopicsClick(Sender: TObject);
begin
    HelpIndex := 8;
    TitrHelpForm.ShowModal;
end;

{LinearPlot determines the appropriate units (milli, micro, etc.) for }
{linear (Molar) plots. This number is YOrd, and is also used for scaling the }
{Y data in the plots.}

Procedure TSweepForm.LinearPlot;
Var    TempMax : double;                {Temporary maximum value for an array}

begin

    {set the Y axis to use units of M, mM, uM, nM, etc.}

    {First find MaxYVal, the largest concentration in the set of 5 plotted}

         MaxYVal := GetAbMax(YData[YSelect.ItemIndex], TitrPts);
         If (Y2Select.ItemIndex > 0) then begin
            TempMax := GetAbMax(YData[Y2Select.ItemIndex], TitrPts);
            If (TempMax > MaxYVal) then MaxYVal := TempMax;
           end;
         If (Y3Select.ItemIndex > 0) then begin
            TempMax := GetAbMax(YData[Y3Select.ItemIndex], TitrPts);
            If (TempMax > MaxYVal) then MaxYVal := TempMax;
          end;
         If (Y4Select.ItemIndex > 0) then begin
            TempMax := GetAbMax(YData[Y4Select.ItemIndex], TitrPts);
            If (TempMax > MaxYVal) then MaxYVal := TempMax;
           end;
         If (Y5Select.ItemIndex > 0) then begin
            TempMax := GetAbMax(YData[Y5Select.ItemIndex], TitrPts);
            If (TempMax > MaxYVal) then MaxYVal := TempMax;
           end;

    {Now calculate Yord, the variable which indicates whether concentrations}
    {are mM, uM, nM, etc.}

         YOrd := -floor(ln(MaxYVal)/(LogConvr*3));
         If (YOrd > 6) then YOrd := 6;
         If (YOrd < 0) then YOrd := 0;

     TitrGraph.LeftAxis.Title.Caption := XUnit[YOrd] + 'olar';
end;                                     {End of LinearPlot}

{When the Log/Molar raio button is changed, LogMolClick gets the current status}
{  ItemIndex = 0  Molar concentration scale
{  ItemIndex = 1  Log Molar scale
{ If a molar scle is to be plotted, the data are scaled via the
{  procedure LinearPlot  }
{  Then all the data are replotted  }

procedure TSweepForm.LogMolClick(Sender: TObject);
begin
   LogMolar := LogMol.ItemIndex;              {Get the scaling type}

   If (LogMolar = 0) then LinearPlot          {Re-scale data for molar plot}
      Else
       TitrGraph.LeftAxis.Title.Caption := 'Log Molar';

   PlotAll;                                   {re-plot the data}

end;



end.




